package collect

import (
	"bufio"
	"context"
	"encoding/json"
	"fmt"
	"github.com/1141520944/go-library/library/log"
	"io"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"
)

func NewFileIO(ctx context.Context, log *log.Logger) *fileIO {
	f := &fileIO{
		files:     make([]*os.File, 0, 10),
		offset:    make([]int64, 0, 10),
		readCount: sync.Map{},
		indexIO:   sync.Map{},
		cxt:       ctx,
		log:       log,
		Create:    make(chan *Create, 10),
		mu:        sync.Mutex{},
	}
	go f.initModifier()
	return f
}
func (f *fileIO) initModifier() {
	for {
		select {
		case v := <-f.Create:
			var (
				err  error
				file *os.File
			)
			//判断是否已经添加过
			_, ok := f.indexIO.Load(v.Path)
			if !ok {
				//创建 IO
				file, err = os.Open(v.Path)
				if err != nil {
					goto end
				}
				//保存索引
				f.indexIO.Store(file.Name(), len(f.files))
				//第一次读取
				f.readCount.Store(file.Name(), false)
				f.mu.Lock()
				f.files = append(f.files, file)
				f.offset = append(f.offset, v.Offset)
				f.mu.Unlock()
				f.log.Infow("add os.FIle ", file.Name())
			}
		end:
			if err != nil {
				f.log.Errorw("method", "fileIO.initModifier create", "err", err.Error())
			}

		case <-f.cxt.Done():
			f.closeAll()
			break
		}
	}
}

// closeAll 关闭文件IO
func (f *fileIO) closeAll() {
	for _, file := range f.files {
		if err := file.Close(); err != nil {
			f.log.Errorw("method", "FileOpt.closeAll", "err", err.Error(), "path", file.Name())
			continue
		}
	}
}
func (f *fileIO) closeFile(path string) (res *Index, err error) {
	var (
		file   *os.File
		index  int
		offset int64
	)
	file, index, offset, err = f.getFile(path)
	if err != nil {
		return
	}
	res.Time = time.Now().Format(time.DateTime)
	res.Offset = offset
	res.Name = file.Name()
	f.indexIO.Delete(file.Name())
	f.readCount.Delete(file.Name())
	//删除索引
	f.mu.Lock()
	copy(f.files[index:], f.files[index+1:])
	f.files = f.files[:len(f.files)]

	copy(f.offset[index:], f.offset[index+1:])
	f.offset = f.offset[:len(f.offset)]
	f.mu.Unlock()
	return res, err
}

// getFile 获得文件IO
func (f *fileIO) getFile(path string) (file *os.File, index int, offset int64, err error) {
	if v, ok := f.indexIO.Load(path); ok {
		index = v.(int)
		file = f.files[index]
		offset = f.offset[index]
		return
	}
	return nil, -1, 0, fmt.Errorf("os.FIle no find")
}

// read 读取
func (f *fileIO) read(path string) (res []string, err error) {
	var (
		file   *os.File
		index  int
		offset int64
		read   bool
		data   []byte
		split  []string
	)
	file, index, offset, err = f.getFile(path)
	if err != nil {
		return nil, err
	}
	//第一次读取
	load, ok := f.readCount.Load(file.Name())
	if ok {
		read = load.(bool)
	} else {
		return nil, nil
	}
	//偏移量
	if _, err = file.Seek(offset, io.SeekStart); err != nil {
		return nil, err
	}
	data, err = io.ReadAll(file)
	if err != nil {
		return nil, err
	}
	offset, err = file.Seek(0, io.SeekCurrent)
	if err != nil {
		return nil, err
	}
	//改变偏移量
	f.offset[index] = offset
	//println(f.offset[index])
	split = strings.Split(string(data), "\n")
	for i, v := range split {
		if i == 0 && read {
			continue
		}
		res = append(res, v)
	}
	if !read {
		f.readCount.Store(index, true)
	}
	return res, nil
}

// write 写入
func (f *fileIO) write(path string, nums []string) (err error) {
	var (
		file *os.File
		w    *bufio.Writer
	)
	file, err = os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err != nil {
		return
	}
	w = bufio.NewWriter(file)
	for _, v := range nums {
		_, err = w.WriteString(v)
		if err != nil {
			w.Flush()
			return
		}
	}
	return w.Flush()
}

// IndexFileWrite 写入索引文件
func (f *fileIO) IndexFileWrite(path string, nums []*Index) (err error) {
	var (
		res []string
	)
	for _, v := range nums {
		var (
			temp []byte
		)
		temp, err = json.Marshal(v)
		if err != nil {
			f.log.Errorw("method", "fileIO.IndexFileWrite json.Marshal", "time", time.Now().Format(time.DateTime), "name", v.Name, "row", v.Row)
			continue
		}
		if len(temp) != 0 {
			res = append(res, string(temp))
		}
	}
	return f.write(path, res)
}

// IndexFileRead 读取索引文件
func (f *fileIO) IndexFileRead(path string) (res []*Index, err error) {
	var (
		file   *os.File
		temp   []string
		reader *bufio.Reader
	)
open:
	file, err = os.Open(path)
	if err != nil {
		//创建文件
		_, err = os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
		goto open
	}
	defer func() {
		if err = file.Close(); err != nil {
			return
		}
	}()
	reader = bufio.NewReader(file)
	for {
		var (
			v string
		)
		v, err = reader.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				break
			}
		}
		temp = append(temp, v)
	}
	if len(temp) == 0 {
		return
	}
	for _, v := range temp {
		// 跳过空行
		if v == "" {
			continue
		}
		// 解析单行JSON数据
		var index Index
		err = json.Unmarshal([]byte(v), &index)
		if err != nil {
			return
		}
		// 将解析的Index添加到切片中
		res = append(res, &index)
	}
	return
}

// LogFileRead 读取日志文件
func (f *fileIO) LogFileRead(path string) (res []*SendLogInfo, err error) {
	var (
		temp []string
	)
	temp, err = f.read(path)
	if err != nil {
		return nil, err
	}
	if len(temp) == 0 {
		return nil, nil
	}
	for _, v := range temp {
		res = append(res, FormatLogData(path, v, time.Now()))
	}
	return
}
func (f *fileIO) GetIndexInfo() ([]*Index, bool) {
	var (
		nowOffset int
		res       []*Index
	)
	if len(f.files) > len(f.offset) {
		return nil, false
	}
	nowOffset = len(f.offset)
	for i := 0; i < nowOffset; i++ {
		res = append(res, &Index{
			Name:   f.files[i].Name(),
			Time:   time.Now().Format(time.DateTime),
			Row:    0,
			Offset: f.offset[i],
		})
	}
	return res, true
}
func (f *fileIO) DelFileIO() []*Index {
	var res []*Index
	f.mu.Lock()
	for _, file := range f.files {
		if checkPath(filepath.Base(file.Name())) {
			continue
		}
		//删除不符合的IO
		temp, err := f.closeFile(file.Name())
		if err != nil {
			f.log.Errorw("method", "FileOpt.FileOpt  f.closeFile", "err", err.Error())
		}
		res = append(res, temp)
	}
	f.mu.Unlock()
	return res
}
